#include "ac_tlm_cache.h"
#include </usr/include/sys/types.h>


using user::ac_tlm_cache;

ac_tlm_cache::ac_tlm_cache( sc_module_name module_name, string nameCache ) : sc_module( module_name ),  DM_port("DM_port", 5242881U){
	/// Binds target_export to the memory
	target_export( *this );
	name = nameCache;
	nVias = 1;
	nLinhas = 256;
	tBloco = 1;
	round_robin = 0;
	hit = 0;
	miss = 0;

	
	memory = new cache_cell*[nVias];
	for(int i=0; i < nVias; i++){
		memory[i] = new cache_cell[nLinhas];
		for(int j=0; j<nLinhas; j++){
			memory[i][j].v = false;
			memory[i][j].data = new uint32_t[tBloco];
			memory[i][j].tag = 0;	
			for(int k=0; k<tBloco; k++){
				memory[i][j].data[k]=0;
			}
			
		}
	}
}


 ///Destructor
ac_tlm_cache::~ac_tlm_cache() {
	for(int i=0; i < nVias; i++){
		for(int j=0; j<nLinhas; j++){
			delete [] memory[i][j].data;
		}
		delete [] memory[i];
	}
	delete [] memory;
	cout << name << endl;
	printf("HIT :%d MISS:%d, MISS RATE:%d %% \n", hit, miss, miss*100/(miss+hit));
	
	/**
	uint32_t a = 1;
	cout << "a:" << a << "\n";
	a = a >> 1;
	cout << "a:" << a << "\n";
	a = a << 10;
	cout << "a:" << a << "\n";
	*/
}


ac_tlm_rsp_status ac_tlm_cache::writem( const uint32_t &a, const uint32_t &d )
{
	
	//cout << "Writing data:  "<< *((uint32_t *) &d) << "\n";
	uint32_t end = a;
	uint32_t boffset = (uint32_t)log2(tBloco);
	uint32_t ioffset = (uint32_t)log2(nLinhas);
	uint32_t toffset = 32 - boffset -  ioffset;
	
	uint32_t tag = end >> (boffset + ioffset) ;
	
	
	uint32_t index = end << (toffset);
	index = index >> (toffset+boffset);
	
	uint32_t block;
	if ((toffset + ioffset) >= 32)
		block =0;
	else
	{
		block = block >> (toffset + ioffset);
		block = block << (toffset + ioffset);
	}
	
	*((uint32_t *) &memory[round_robin][index].data[block]) = *((uint32_t *) &d);
	
	//cout << *((uint32_t *) &memory[round_robin][index].data[block]) << "\t"<<*((uint32_t *) &d) << "\n ";
	
	
	memory[round_robin][index].tag = tag;
	memory[round_robin][index].v = true;
	
	//cout << "Writing at "<< a << "index "<< index <<"\n";
	
	return SUCCESS;
}

ac_tlm_rsp_status ac_tlm_cache::readm( const uint32_t &a,  uint32_t &d )
{
	
	
	uint32_t end = a;
	uint32_t boffset = (uint32_t)log2(tBloco);
	//cout << "Valor de boffset "<< boffset << "\n";
	uint32_t ioffset = (uint32_t)log2(nLinhas);
	//cout << "Valor de ioffset "<< ioffset << "\n";
	uint32_t toffset = 32 - boffset -  ioffset;
	//cout << "Valor de toffset "<< toffset << "\n";
	
	
	uint32_t tag = end >> (boffset + ioffset) ;
	//cout << "Valor da tag "<< tag << "\n";
	
	uint32_t index = end << (toffset);
	index = index >> (toffset+boffset);
	//cout << "Valor da index "<< index << "\n";
	
	
	uint32_t block;
	if ((toffset + ioffset) >= 32)
		block =0;
	else
	{
		block = block >> (toffset + ioffset);
		block = block << (toffset + ioffset);
	}
	//block = block >> (toffset + ioffset);
	//cout << "Valor do bloco "<< block << "\n";
	
	if(memory[round_robin][index].v == true && memory[round_robin][index].tag == tag )
	{
		*((uint32_t *) &d) = *((uint32_t *) &memory[round_robin][index].data[block]);
		//cout << "HIT, DEVOLVENDO PARA O PROCESSADOR"<<"\n";
		hit++;
		return SUCCESS;
	}
	miss++;
	
	//cout << "Reading at "<< a << "index "<< index <<"\n";
	
	return ERROR;
	
	//return SUCCESS;
}

